#include"MetaDataEditor.h" 

#include<QDir>

#include"LFMCorrection.h"
#include"Song.h"//Shouldn't really be here...

QList<void (*)(void*, QList<QString>)> MetaDataEditor::s_callbacksOnExit = QList<void (*)(void*, QList<QString>)>();
QList<void*> MetaDataEditor::s_callbackObjects = QList<void*>();

void MetaDataEditor::addCallbackOnChange( void (*callbackOnChange)(void*,QList<QString>), void *obj ){
	s_callbackObjects.push_back(obj);
	s_callbacksOnExit.push_back(callbackOnChange);
}

MetaDataEditor::MetaDataEditor(QList<QString> songPaths):QDialog(0){
	setAttribute(Qt::WA_DeleteOnClose);
	m_autoExitTimer = 0;
	
	m_layout = new QVBoxLayout(this);
	setLayout(m_layout);
	
	m_tabWidget = new QTabWidget(this);
	m_layout->addWidget(m_tabWidget);
	
	m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel, Qt::Horizontal, this);
	connect(m_buttons, SIGNAL(clicked(QAbstractButton*)), this, SLOT(slotButtonClicked(QAbstractButton*)));
	m_layout->addWidget(m_buttons);
	
	for(int i = 0; i < songPaths.size(); i++){
		if(songPaths[i].isEmpty())
			continue;
		m_fileRef.push_back(TagLib::FileRef(songPaths[i].toUtf8().data()));
		if(m_fileRef.last().isNull()){
			QMessageBox::critical(this, "Error", "Couldn't open one of the songs. DO NOT USE THIS EDITOR!!");
			return;
		}
		m_tag.push_back( m_fileRef.last().tag() );
	}
	
	if(m_tag.size()>1){//More than one song, requires a page for global settings
		initGlobalEditor();
	}else{
		m_editWidgetGlobal = 0;
		m_editLayoutGlobal = 0;
		m_editArtistGlobal = 0;
		m_editAlbumGlobal = 0;
		m_editTrackGlobal = 0;
	}
	
	for(int i = 0; i < m_tag.size(); i++){
		m_editWidget.push_back( new QWidget(m_tabWidget) );
		m_tabWidget->addTab(m_editWidget[i], QString().setNum(i+1));
		
		m_editLayout.push_back( new QFormLayout(m_editWidget[i]) );
		m_editWidget[i]->setLayout(m_editLayout[i]);
		
		
		m_editLayout[i]->addRow( new QLabel(songPaths[i], this) );
		
		m_editTitle.push_back( new QLineEdit(m_editWidget[i]) );
		m_editTitle[i]->setText(m_tag[i]->title().toCString());
		connect(m_editTitle[i], SIGNAL(textEdited(QString)), this, SLOT(slotAnythingChanged()));
		m_editLayout[i]->addRow("Title", m_editTitle[i]);
		
		m_editArtist.push_back( new QLineEdit(m_editWidget[i]) );
		m_editArtist[i]->setText(m_tag[i]->artist().toCString());
		connect(m_editArtist[i], SIGNAL(textEdited(QString)), this, SLOT(slotAnythingChanged()));
		m_editLayout[i]->addRow("Artist", m_editArtist[i]);
		
		m_editAlbum.push_back( new QLineEdit(m_editWidget[i]) );
		m_editAlbum[i]->setText(m_tag[i]->album().toCString());
		connect(m_editAlbum[i], SIGNAL(textEdited(QString)), this, SLOT(slotAnythingChanged()));
		m_editLayout[i]->addRow("Album", m_editAlbum[i]);
		
		m_editTrack.push_back( new QLineEdit(m_editWidget[i]) );
		m_editTrack[i]->setValidator(new QIntValidator);
		m_editTrack[i]->setText(QString().setNum(m_tag[i]->track()));
		connect(m_editTrack[i], SIGNAL(textEdited(QString)), this, SLOT(slotAnythingChanged()));
		m_editLayout[i]->addRow("Track #", m_editTrack[i]);
	}
	connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotAnythingChanged()));
}

void MetaDataEditor::initGlobalEditor(){
	m_editWidgetGlobal = new QWidget(m_tabWidget);
	m_tabWidget->addTab(m_editWidgetGlobal, "Global");
	
	m_editLayoutGlobal = new QFormLayout(m_editWidgetGlobal);
	m_editWidgetGlobal->setLayout(m_editLayoutGlobal);
	
	m_editLayoutGlobal->addRow(new QLabel("Global settings", this));
	
	QWidget *widget = 0;
	QHBoxLayout *layout = 0;
	QCheckBox *checkbox = 0;
	
	widget = new QWidget(m_editWidgetGlobal);
	layout = new QHBoxLayout(widget);
	widget->setLayout(layout);
	m_editArtistGlobal = new QLineEdit(widget);
	m_editArtistGlobal->setText(m_tag[0]->artist().toCString());
	m_editArtistGlobal->setReadOnly(true);
	layout->addWidget(m_editArtistGlobal);
	checkbox = new QCheckBox(widget);
	checkbox->setChecked(false);
	connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(slotGlobalArtistStateChanged(int)));
	layout->addWidget(checkbox);
	m_editLayoutGlobal->addRow("Artist", widget);
	
	widget = new QWidget(m_editWidgetGlobal);
	layout = new QHBoxLayout(widget);
	widget->setLayout(layout);
	m_editAlbumGlobal = new QLineEdit(widget);
	m_editAlbumGlobal->setText(m_tag[0]->album().toCString());
	m_editAlbumGlobal->setReadOnly(true);
	layout->addWidget(m_editAlbumGlobal);
	checkbox = new QCheckBox(widget);
	checkbox->setChecked(false);
	connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(slotGlobalAlbumStateChanged(int)));
	layout->addWidget(checkbox);
	m_editLayoutGlobal->addRow("Album", widget);
	
	m_editTrackGlobal = new QCheckBox("Number automatically", this);
	m_editTrackGlobal->setChecked(false);
	m_editLayoutGlobal->addRow("Track #", m_editTrackGlobal);
	
	connect(m_editArtistGlobal, SIGNAL(textEdited(QString)), this, SLOT(slotGlobalArtistChanged(QString)));
	connect(m_editAlbumGlobal, SIGNAL(textEdited(QString)), this, SLOT(slotGlobalAlbumChanged(QString)));
	connect(m_editTrackGlobal, SIGNAL(stateChanged(int)), this, SLOT(slotAutoNumberingChanged(int)));
}

#include<stdio.h>
MetaDataEditor::~MetaDataEditor(){
	printf("~MetaDataEditor\n");
}

void MetaDataEditor::slotButtonClicked(QAbstractButton *button){
	if(button->text() == "OK")
		buttonOk();
	else if(button->text() == "Cancel")
		buttonCancel();
	else if(button->text() == "Apply")
		buttonApply();
	else
		printf("MetaDataEditor::Unrecognized button: %s\n", button->text().toUtf8().data());
}

void MetaDataEditor::buttonCancel(){
	done(QDialog::Rejected);
}

void MetaDataEditor::buttonOk(){
	if( buttonApply() )
		done(QDialog::Accepted);
}

bool MetaDataEditor::buttonApply(){
	if( QMessageBox::question(this, "Confirmation", "Are you sure you wish to write this to file?", QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel )
		return false;
	QList<QString> filenames;
	for(int i = 0; i < m_tag.size(); i++){
		m_tag[i]->setTitle( TagLib::String(m_editTitle[i]->text().toUtf8().data(), TagLib::String::UTF8) );
		m_tag[i]->setArtist( TagLib::String(m_editArtist[i]->text().toUtf8().data(), TagLib::String::UTF8) );
		m_tag[i]->setAlbum( TagLib::String(m_editAlbum[i]->text().toUtf8().data(), TagLib::String::UTF8) );
		m_tag[i]->setTrack(m_editTrack[i]->text().toUInt());
		m_fileRef[i].save();
		
		if(s_callbacksOnExit.size())
			filenames.push_back(QString::fromUtf8(m_fileRef[i].file()->name()));
	}
	
	for(int i = 0; i < s_callbacksOnExit.size(); i++)
		s_callbacksOnExit[i](s_callbackObjects[i], filenames);
// 	if(s_callbackOnExit)
// 		s_callbackOnExit(s_callbackObject, filenames);
	
	return true;
}

void MetaDataEditor::launchEditor(QList<QString> songPaths){
	printf("MetaDataEditor should be launched for:\n");
	for(int i = 0; i < songPaths.size(); i++)
		printf("\t%s\n", songPaths[i].toUtf8().data());
	if(songPaths.size()){
		MetaDataEditor *editor = new MetaDataEditor(songPaths);
		editor->setWindowTitle("MetaDataEditor");
		editor->show();
	}
}

void MetaDataEditor::launchEditorForCorrection(LFMCorrection *correction){
	QList<QString> songPaths;
	songPaths.push_back(correction->path);
	_addMorePathsToCorrection(songPaths, correction);
	MetaDataEditor *editor = new MetaDataEditor(songPaths);
	editor->applyCorrection(correction);
	editor->setTimer(60000);
	editor->setWindowTitle("Automatic MetaDataEditor For Correction by Last.FM");
	editor->show();
	
}

void MetaDataEditor::_addMorePathsToCorrection(QList<QString> &songPaths, LFMCorrection *correction){
	if(!correction || correction->titleCorrected)
		return;
	QString dirName = correction->path;
	dirName.truncate(dirName.lastIndexOf(QDir::separator()));
	QDir dir(dirName);
	if(!dir.exists())
		return;
	//WARNING Dirty business here :/
	for(uint i = 0; i < dir.count(); i++){
		try{
			Song *song = new Song(dir.absoluteFilePath(dir[i]));
			if(!songPaths.contains(song->path()))
				songPaths.push_back(song->path());
			delete song;
		}catch(SongException){
		
		}
	}
}

void MetaDataEditor::applyCorrection(LFMCorrection *correction){
	if(m_editArtistGlobal && correction->artistCorrected)
		m_editArtistGlobal->setText(correction->artist);
	if(m_editAlbumGlobal && correction->albumCorrected)
		m_editAlbumGlobal->setText(correction->album);
	for(int i = 0; i < m_editTitle.size(); i++){
		if(correction->artistCorrected)
			m_editArtist[i]->setText(correction->artist);
		if(correction->albumCorrected)
			m_editAlbum[i]->setText(correction->album);
		if(correction->titleCorrected && i == 0)//WARNING: Not sure if should always expect corrected track to be first.
			m_editTitle[i]->setText(correction->title);
	}
}

void MetaDataEditor::setTimer(qint64 duration){
	m_autoExitTimer = new QTimer(this);
	connect(m_autoExitTimer, SIGNAL(timeout()), this, SLOT(buttonCancel()));
	m_autoExitTimer->setSingleShot(true);
	m_autoExitTimer->start(duration);
}

void MetaDataEditor::slotAnythingChanged(){
	if(m_autoExitTimer){
		QTimer *copy = m_autoExitTimer;
		m_autoExitTimer = 0;
		copy->stop();
		copy->disconnect();
		delete copy;
	}
}

void MetaDataEditor::slotAutoNumberingChanged(int state){
	if(state){
		for(int i = 0; i < m_editTrack.size(); i++)
			m_editTrack[i]->setText(QString().setNum(i+1));
	}else{
		for(int i = 0; i < m_editTrack.size(); i++)
			m_editTrack[i]->setText(QString().setNum( m_tag[i]->track() ));
	}
}

void MetaDataEditor::slotGlobalArtistChanged(QString newArtist){
	for(int i = 0; i < m_editArtist.size(); i++)
		m_editArtist[i]->setText(newArtist);
}

void MetaDataEditor::slotGlobalArtistStateChanged(int state){
	m_editArtistGlobal->setReadOnly(!state);
}

void MetaDataEditor::slotGlobalAlbumChanged(QString newAlbum){
	for(int i = 0; i < m_editAlbum.size(); i++)
		m_editAlbum[i]->setText(newAlbum);
}

void MetaDataEditor::slotGlobalAlbumStateChanged(int state){
	m_editAlbumGlobal->setReadOnly(!state);
}
